def crc_cal16(data)
  crc = 0xFFFF
  data.each_char.each_slice(2) do |byte|
    byte = byte.join.to_i(16)
    byte &= 0x00FF
    crc ^= byte
    8.times do
      if crc.odd?
        crc >>= 1
        crc ^= 0xA001
      else
        crc >>= 1
      end
    end
  end
  crc = format "%04X", crc
  crc[2, 2] + crc[0, 2]
end

def modbus_mutli(addr, ctrl_size, data_size, data)
  res = '010F'
  res << format("%04X", addr)
  res << format("%04X", ctrl_size)
  res << format("%02X", data_size)
  res << format("%02X", data)
  res << crc_cal16(res)
end

def modbus_single(addr, isopen)
  res = '0105'
  res << format("%04X", addr)
  res << (isopen ? 'FF00' : '0000')
  res << crc_cal16(res)
end

def modbus_collect(addr, data)
  res = '0102'
  res << format("%04X", addr)
  res << format("%04X", data)
  res << crc_cal16(res)
end

def test_collect
  modbus_collect 0, 8
end

def test_single
  modbus_single 0, true
end

def test_mutli
  modbus_mutli 0, 8, 1, 'A4'.to_i(16)
end

def main()
  fn_name = "modbus_#{ARGV.first}"
  ARGV.each do |fn_name|
    begin
      res = send "test_#{fn_name}"
      puts res
    rescue => e
      puts e
      puts e.backtrace
    end
  end
end

main
